use axum_app_common::{
    database::{self, RawSqlQueryBuilder},
    error::BizError,
    model::*,
    my_date_format, service_store,
    validator::RequestValidatorField,
    BizHandler, BizHandlerResult, ServiceStore,
};
use axum_app_dao::{entity::sys_role, role_dal};
use chrono::{DateTime, Utc};
use sea_orm::{FromQueryResult, PaginatorTrait, Set};
use serde::Serialize;
use serde_json::json;

use crate::model::role::{RoleCreateParams, RoleDeleteParams, RoleQueryParams, RoleUpdateParams};

pub struct RoleHandler;

impl BizHandler for RoleHandler {
    fn service_map() -> ServiceStore {
        service_store! {
            ("role.query.page","分页查询角色信息") => query_page;
            ("role.create","创建角色信息")  => create_role;
            ("role.update","更新角色信息")  => update_role;
            ("role.delete","删除角色信息")  => delete_role
        }
    }
}

#[derive(Debug, FromQueryResult, Serialize)]
pub struct RoleItem {
    pub id: i64,
    pub role_code: String,
    pub role_name: String,
    pub role_description: String,
    #[serde(with = "my_date_format")]
    pub create_time: DateTime<Utc>,
    #[serde(with = "my_date_format")]
    pub update_time: DateTime<Utc>,
}

/// 分页查询角色信息
pub async fn query_page(request: BizRequest) -> BizHandlerResult {
    let _ = request.get_context();
    let state = request.get_state().unwrap();
    let db = &state.db_conn;

    let biz_content = request.get_biz_content();

    let params = PageRequest::<RoleQueryParams>::try_from(biz_content)?;
    let page_num = params.page_num as u32;
    let page_size = params.page_size as u32;

    let base_sql = "
SELECT 
	r.id, 
    r.role_code, 
    r.role_name, 
    r.role_description, 
    r.create_time, 
    r.update_time
FROM sys_role r 
    ";
    let mut sql_builder = RawSqlQueryBuilder::new();

    let Some(query_params) = params.params else {
        return Err(BizError::InvalidParams(None).into());
    };

    if !query_params.role_code.is_blank() {
        sql_builder.push_bind("and r.role_code=", query_params.role_code.into());
    }
    if !query_params.role_name.is_blank() {
        sql_builder.push_bind(
            "and r.role_name like ",
            format!("%{}%", query_params.role_name.unwrap()).into(),
        );
    }

    if !query_params.bound_user.is_blank() {
        sql_builder.push(
            "and exists (
            select rel.id from rbac_user_role_rel rel where rel.role_code=r.role_code ",
        );
        sql_builder.push_bind("and rel.user_id=", query_params.bound_user.into());
        sql_builder.push(")");
    }

    if !query_params.unbound_user.is_blank() {
        sql_builder.push(
            "and not exists (
            select rel.id from rbac_user_role_rel rel where rel.role_code=r.role_code ",
        );
        sql_builder.push_bind("and rel.user_id=", query_params.unbound_user.into());
        sql_builder.push(")");
    }

    sql_builder.push("and r.delete_flag=0");

    let sql_and_vals = sql_builder.build(&base_sql, Some("r.role_name asc"));

    let stmt = database::from_string_values_tuple(sql_and_vals);
    let selector = RoleItem::find_by_statement(stmt);

    let pager = selector.paginate(db, page_size as u64);
    let page_list = pager.fetch_page((page_num - 1) as u64).await.unwrap();
    let total = pager.num_items().await.unwrap();

    let data = PageResult::new(page_num as u64, page_size as u64, total as u64, page_list);
    Ok(BizResponse::success(data.into()))
}

/// 创建角色
pub async fn create_role(request: BizRequest) -> BizHandlerResult {
    let state = request.get_state().unwrap();
    let db = &state.db_conn;

    let params = request.get_biz_model::<RoleCreateParams>()?;

    let RoleCreateParams {
        role_code,
        role_name,
        role_description,
    } = params;

    let res = role_dal::insert(
        db,
        &role_code,
        &role_name,
        role_description.unwrap_or_default().as_str(),
    )
    .await?;

    Ok(BizResponse::success(res.into()))
}

/// 更新角色信息
pub async fn update_role(request: BizRequest) -> BizHandlerResult {
    let state = request.get_state().unwrap();
    let db = &state.db_conn;

    let params = request.get_biz_model::<RoleUpdateParams>()?;

    let code = params.role_code;

    let find_role_by_code = role_dal::RoleQuery::find_role_by_code(db, &code).await?;

    let Some(_) = find_role_by_code else {
        return Ok(BizResponse::fail_with_biz_error(
            BizError::DataNotFound,
            None,
        ));
    };

    let name = params.role_name;
    let desc = params.role_description;

    let res = role_dal::update_by_code(db, &code, Some(&name), desc.as_deref()).await?;

    Ok(BizResponse::success(res.into()))
}

/// 删除角色信息
pub async fn delete_role(request: BizRequest) -> BizHandlerResult {
    let state = request.get_state().unwrap();
    let db = &state.db_conn;

    let params = request.get_biz_model::<RoleDeleteParams>()?;

    let code = params.role_code;

    let find_role_by_code = role_dal::RoleQuery::find_role_by_code(db, &code).await?;

    let Some(mut role) = find_role_by_code else {
        return Ok(BizResponse::fail_with_biz_error(
            BizError::DataNotFound,
            None,
        ));
    };

    role.delete_flag = role.id;

    let res = role_dal::update_by_id(
        db,
        role.id as u64,
        sys_role::ActiveModel {
            delete_flag: Set(role.id),
            ..Default::default()
        },
    )
    .await?;

    Ok(BizResponse::success(json!(res)))
}
